#pragma once
#include<brpc/server.h>
#include<butil/logging.h>
#include "etcd.hpp"     
#include "logger.hpp"   
#include "utils.hpp"
#include "base.pb.h"
#include "file.pb.h"
namespace zzy_mims
{
    class FileServiceImpl:public FileService
    {
    public:
        FileServiceImpl(const std::string& storage_path)
        :_storage_path(storage_path)
        {
            umask(0);
            mkdir(storage_path.c_str(),0775);
            if(_storage_path.back()!='/') _storage_path+='/';
        };
        ~FileServiceImpl(){};
        void GetSingleFile(google::protobuf::RpcController* controller,
        const ::zzy_mims::GetSingleFileReq* request, 
        ::zzy_mims::GetSingleFileRsp* response, 
        ::google::protobuf::Closure* done)
        {
            brpc::ClosureGuard rpc_guard(done);//和RAII思想类似，在局部域结束后自动调用done->Run();
            //1.设置请求id并得到要获取的文件的名字
            response->set_request_id(request->request_id());
            std::string fid = request->file_id();
            std::string filename =_storage_path+fid;
            LOG_DEBUG("开始获取{}文件数据\n",filename);
            //2.通过文件名字读取文件数据
            std::string body;
            bool ret = readFile(filename,body);
            if(ret==false)
            {
                response->set_success(false);
                response->set_errmsg("读取文件失败");
                LOG_ERROR("请求:{}读取文件数据失败\n",request->request_id());
                return;
            }
            //3.组织回应
            response->set_success(true);
            response->mutable_file_data()->set_file_id(fid);
            response->mutable_file_data()->set_file_content(body);
        };
        void GetMultiFile(google::protobuf::RpcController* controller,
        const ::zzy_mims::GetMultiFileReq* request, 
        ::zzy_mims::GetMultiFileRsp* response, 
        ::google::protobuf::Closure* done)
        {
            brpc::ClosureGuard rpc_guard(done);//和RAII思想类似，在局部域结束后自动调用done->Run();
            response->set_request_id(request->request_id());
            std::string body;
            for(int i =0;i<request->file_id_list_size();i++)
            {
                std::string fid =request->file_id_list(i);
                std::string filename = _storage_path+fid;
                LOG_DEBUG("开始获取{}文件数据\n",filename);
                bool ret = readFile(filename,body);
                if(ret==false)
                {
                    response->set_success(false);
                    response->set_errmsg("读取文件失败");
                    LOG_ERROR("请求:{}读取文件数据失败\n",request->request_id());
                    return;
                }
                FileDownloadData data;
                data.set_file_id(fid);
                data.set_file_content(body);
                response->mutable_file_data()->insert({fid,data});
            }
            response->set_success(true);
        }
        void PutSingleFile(google::protobuf::RpcController* controller,
        const ::zzy_mims::PutSingleFileReq* request, 
        ::zzy_mims::PutSingleFileRsp* response, 
        ::google::protobuf::Closure* done)
        {
            brpc::ClosureGuard rpc_guard(done);//和RAII思想类似，在局部域结束后自动调用done->Run();
            response->set_request_id(request->request_id());
            //1.为文件生成一个文件名
            std::string fid = uuid();
            std::string filename = _storage_path+fid;
            //2.取出请求中的数据，进行文件数据写入
            bool ret = writeFile(filename,request->file_data().file_content());
            if(ret==false)
            {
                response->set_success(false);
                response->set_errmsg("写入文件失败");
                LOG_ERROR("请求:{}写入文件数据失败\n",request->request_id());
                return;
            }
            response->set_success(true);
            response->mutable_file_info()->set_file_id(fid);
            response->mutable_file_info()->set_file_size(request->file_data().file_size());
            response->mutable_file_info()->set_file_name(request->file_data().file_name());
        };
        void PutMultiFile(google::protobuf::RpcController* controller,
        const ::zzy_mims::PutMultiFileReq* request, 
        ::zzy_mims::PutMultiFileRsp* response, 
        ::google::protobuf::Closure* done)
        {
            brpc::ClosureGuard rpc_guard(done);//和RAII思想类似，在局部域结束后自动调用done->Run();
            response->set_request_id(request->request_id());
            for(int i =0;i<request->file_data_size();i++)
            {
                //1.为文件生成一个文件名
                std::string fid = uuid();
                std::string filename = _storage_path+fid;
                //2.取出请求中的数据，进行文件数据写入
                bool ret = writeFile(filename,request->file_data(i).file_content());
                if(ret==false)
                {
                    response->set_success(false);
                    response->set_errmsg("写入文件失败");
                    LOG_ERROR("请求:{}写入文件数据失败\n",request->request_id());
                    return;
                }
                FileMessageInfo* info = response->add_file_info();
                info->set_file_id(fid);
                info->set_file_size(request->file_data(i).file_size());
                info->set_file_name(request->file_data(i).file_name());
            }
            response->set_success(true);

        }
    private:
        std::string _storage_path;
    };

    class FileServer
    {
    public:
        using ptr = std::shared_ptr<FileServer>;
        FileServer(const Registery::ptr& reg_client,const std::shared_ptr<brpc::Server>& rpc_server)
        :_reg_client(reg_client),_rpc_server(rpc_server){};
        ~FileServer(){};
        void start()
        {
            _rpc_server->RunUntilAskedToQuit();
        };
    private:
        Registery::ptr _reg_client;
        std::shared_ptr<brpc::Server> _rpc_server;
    };
    class FileServerBuilder
    {
    public:
        void make_reg_object(const std::string& reg_host,
                            const std::string& service_name,
                            const std::string& access_host)
        {
            _reg_client = std::make_shared<Registery>(reg_host);
            _reg_client->Register(service_name,access_host);
        }
        void make_rpc_server(uint16_t port,int32_t timeout,uint8_t num_threads,const std::string& storage_path = "./data/")
        {
            _rpc_server = std::make_shared<brpc::Server>();
            FileServiceImpl* file_service = new FileServiceImpl(storage_path);
            int ret = _rpc_server->AddService(file_service,brpc::ServiceOwnership::SERVER_OWNS_SERVICE);
            if(ret==-1)
            {
                LOG_ERROR("添加RPC服务失败!");
                abort();
            }
            brpc::ServerOptions options;
            options.idle_timeout_sec=timeout;
            options.num_threads = num_threads;
            ret = _rpc_server->Start(port,&options);
            if(ret==-1)
            {
                LOG_ERROR("speech_RPC服务器启动失败");
                abort();
            }
        }
        FileServer::ptr build()
        {
            if (!_reg_client) {
                LOG_ERROR("还未初始化服务注册模块！");
                abort();
            }
            if (!_rpc_server) {
                LOG_ERROR("还未初始化RPC服务器模块！");
                abort();
            }
            FileServer::ptr server = std::make_shared<FileServer>(_reg_client, _rpc_server);
            return server;
        }

    private:
        Registery::ptr _reg_client;
        std::shared_ptr<brpc::Server> _rpc_server;
    };
};

